package se.webbzon.boltzmann.game.object.spawner;

import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;

import se.webbzon.boltzmann.battle.environment.BattleEnvironment;
import se.webbzon.boltzmann.battle.property.BattlePropertyFactory;
import se.webbzon.boltzmann.battle.property.BattlePropertyFactoryGroup;
import se.webbzon.boltzmann.debug.Debug;
import se.webbzon.boltzmann.environment.AbstractEnvironment;
import se.webbzon.boltzmann.game.character.CharacterException;
import se.webbzon.boltzmann.game.object.npc.HostileAI;
import se.webbzon.boltzmann.game.object.npc.HostileNPC;
import se.webbzon.boltzmann.npc.NPCDuty;
import se.webbzon.boltzmann.object.unknown.Unknown;
import se.webbzon.oschi01.friendly.Friendly;
import se.webbzon.oschi01.worldobject.WorldObject;
import se.webbzon.oschi01.worldobject.WorldStaticObject;

public class HostileNPCSpawnerDeflation extends AbstractNPCSpawnerDeflation {
	
	private HostileAI ai;
	
	private String worldAreaName;
	
	private final List<String> battlePropertyFactoryNames;
	
	/*============================================================
	Constructors
	============================================================*/
	
	public HostileNPCSpawnerDeflation(int deflationProperties) {
		super(deflationProperties);
		battlePropertyFactoryNames = new ArrayList<String>();
	}
	
	public HostileNPCSpawnerDeflation(	int deflationProperties, 
										HostileNPCSpawner spawner) {
		super(deflationProperties,spawner);
		ai = spawner.getAI();
		worldAreaName = spawner.getWorldAreaName();
		battlePropertyFactoryNames = new ArrayList<String>();
		for (BattlePropertyFactory factory : spawner.getBattlePropertyFactories())
			battlePropertyFactoryNames.add(factory.getName());
	}
	
	/*============================================================
	Public Methods
	============================================================*/
	
	@Override public void inflate(ByteBuffer buff) {
		super.inflate(buff);
		short size;
		byte[] data;
		
		// Read the artificial intelligence enumeration
		ai = HostileAI.values()[buff.getInt()];
		
		// Read the world area name
		size = buff.getShort();
		data = new byte[size];
		buff.get(data,0,size);
		try {
			worldAreaName = new String(data,"UTF-8");
		} catch (UnsupportedEncodingException e) {
			// Do nothing
		}
		
		// Read battle property factory names
		short factoryNames = buff.getShort();
		try {
			for (int i = 0; i < factoryNames; i++) {
				size = buff.getShort();
				data = new byte[size];
				buff.get(data,0,size);
				battlePropertyFactoryNames.add(new String(data,"UTF-8"));
			}
		} catch (UnsupportedEncodingException e) {
			// Do nothing
		}
	}

	@Override public ByteBuffer deflate(int allocate) {
		byte[] worldAreaNameData;
		ArrayList<byte[]> battlePropertyFactoryNameDatas = new ArrayList<byte[]>();
		int size = 4;
		
		// Calculate the size of the world area name
		try {
			worldAreaNameData = worldAreaName.getBytes("UTF-8");
			size += 2 + worldAreaNameData.length;
		} catch (UnsupportedEncodingException e) {
			worldAreaNameData = new byte[0];
		}
		
		// Calculate the size of the battle property factory names
		size += 2;
		try {
			for (String battlePropertyFactoryName : battlePropertyFactoryNames) {
				final byte[] data = 
						battlePropertyFactoryName.getBytes("UTF-8");
				battlePropertyFactoryNameDatas.add(data);
				size += 2 + data.length;
			}
		} catch (UnsupportedEncodingException e) {
			// Do nothing
		}
		
		// Write to the buffer
		ByteBuffer buff = super.deflate(size + allocate);
		
		buff.putInt(ai.ordinal());
		buff.putShort((short) worldAreaNameData.length);
		buff.put(worldAreaNameData);
		buff.putShort((short) battlePropertyFactoryNameDatas.size()); 
		for (byte[] data : battlePropertyFactoryNameDatas) {
			buff.putShort((short) data.length);
			buff.put(data);
		}
		
		return buff;
	}
	
	/*============================================================
	Friendly Methods
	============================================================*/
	
	@Friendly WorldObject createSpawnerOrNPC(	
										AbstractEnvironment env, 
										BattleEnvironment benv,
										BattlePropertyFactoryGroup factoryGroup) {
		WorldStaticObject instance = null;
		NPCDuty d = null;
		final double dy;
		
		if (!spawn(env)) {
			// Generate spawner
			HostileNPCSpawner spawner = 
					new HostileNPCSpawner(	getId(), getKey(),
											getCharacterTextureSetName(), 
											ai, worldAreaName);
			
			for (String battlePropertyFactoryName : battlePropertyFactoryNames) 
				spawner.addBattlePropertyFactory(
						factoryGroup.getFactory(battlePropertyFactoryName));
			spawner.setVisible(env.isDebugMode());
			instance = spawner;
			dy = 0;
		} else try {
			// Generate npc
			ArrayList<BattlePropertyFactory> factories = 
					new ArrayList<BattlePropertyFactory>();
			for (String battlePropertyFactoryName : battlePropertyFactoryNames) 
				factories.add(
						factoryGroup.getFactory(battlePropertyFactoryName));
			
			HostileNPC npc = new HostileNPC(getCharacterTextureSetName(),benv,ai,
											factories,worldAreaName);
			d = npc.getDuty();
			instance = npc;
		} catch (CharacterException e) {
			// Generate unknown
			Debug.report(e);
			instance = new Unknown();
		} finally {
			dy = 0.5;
		}
		
		instance.setPosition(getX(), getY()+dy, getZ());
		instance.setSize(getWidth(), getHeight(), getDepth());
		instance.setRotation(getEX(), getEY(), getEZ(), getAngle());
		if (d != null)
			d.setOrigin(getX(), getY(), getZ());
		
		return instance;
	}
	

}
